#pragma once

#include <string>
#include <functional>
#include <jsoncpp/json/json.h>
#include "Log.h"
#include "Socket.h"

#define Sep "\r\n"

namespace zmh
{
    class Request // 客户端的请求
    {
    public:
        Request() = default;
        Request(int x, int y, int oper)
            : _x(x), _y(y), _oper(oper) {}

        void Deserialize(std::string data)
        {
            Json::Value root;
            Json::Reader reader;

            if (reader.parse(data, root) == false)
            {
                LOG(WARNING) << "Request::Deserialize::reader.parse mistake";
                return;
            }

            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        std::string Serialize() const
        {
            Json::Value root;
            root["x"] = _x;
            root["y"] = _y;
            root["oper"] = _oper;

            Json::FastWriter writer;
            return writer.write(root);
        }
        int X() const
        {
            return _x;
        }
        int Y() const
        {
            return _y;
        }
        int Oper() const
        {
            return _oper;
        }

    private:
        int _x;    // 操作符的左参数
        int _y;    // 操作符的右参数
        int _oper; // 操作符
    };
    class Response // 服务端的回应
    {
    public:
        Response() = default;
        Response(int result, int status = 0)
            : _result(result), _status(status) {}

        static std::string Outstatus(int status)
        {
            std::string statusInfo[] = {"NORMAL", "mistake: '/\' 0", "mistake: '%' 0", "mistake: 非法操作"};
            return statusInfo[status];
        }

        void Deserialize(std::string data)
        {
            Json::Value root;
            Json::Reader reader;

            if (reader.parse(data, root) == false)
            {
                LOG(WARNING) << "Response::Deserialize::reader.parse mistake";
                return;
            }

            _result = root["result"].asInt();
            _status = root["status"].asInt();
        }
        std::string Serialize()
        {
            Json::Value root;
            root["result"] = _result;
            root["status"] = _status;

            Json::FastWriter writer;
            return writer.write(root);
        }
        int Result()
        {
            return _result;
        }
        int Status()
        {
            return _status;
        }

    private:
        int _result;
        int _status;
    };

    class Protocol
    {
    public:
        void EnHeader(std::string &buffer) // 添加报头
        {
            buffer = std::to_string(buffer.size()) + Sep + buffer + Sep;
        }

        // 报文格式:len\n\r{"oper":10,"x":1,"y":2}\n\r
        bool DeHeader(std::string &buffer, std::string &out) // 从缓冲区buffer中,提取完整报文,并移除报头
        {
            size_t pos = buffer.find(Sep); // 字串\n\r的起始位置
            if (pos == std::string::npos)
                return false;
            std::string header = buffer.substr(0, pos); // 获取报头信息
            size_t str_len = std::stoi(header);         // 正文长度
            size_t len = header.size() + str_len + 2 * strlen(Sep);
            if (buffer.size() < len)
                return false;
            out = buffer.substr(pos + strlen(Sep), str_len);
            buffer.erase(0, len);
            return true;
        }

        void GetRequest(std::shared_ptr<zmh::Socket> Socket, const std::function<Response(Request)> &func)
        {
            std::string buffer; // 提供缓冲区
            while (true)
            {
                if (Socket->recv(buffer) == 0)
                    break;
                std::string out;
                while (DeHeader(buffer, out) == true)
                {
                    LOG(zmh::INFO) << out;

                    Request req;
                    req.Deserialize(out);

                    // 协议层完成数据格式转换后,剩下的是上层模块的任务 --- 完成计算功能
                    Response rep = func(req);

                    std::string in = rep.Serialize();
                    EnHeader(in);
                    Send(Socket, in);
                }
            }
        }
        /*也可以提供一个仿函数参数,表示你要如何处理该数据,这里就把结果带出去*/
        void GetResponse(std::shared_ptr<zmh::Socket> Socket, const std::function<void(Response)> &func)
        {
            std::string buffer; // 提供缓冲区
            while (true)
            {
                if (Socket->recv(buffer) == 0)
                    return;
                std::string out;
                if (DeHeader(buffer, out) == true)
                {
                    Response req;
                    req.Deserialize(out);
                    func(req);
                    return;
                }
            }
        }
        void Send(std::shared_ptr<zmh::Socket> Socket, std::string message)
        {
            if (Socket->send(message) == -1)
                LOG(ERROR) << "Socket->send(message) mistake";
        }
    };
}